package com.zcxy.sys.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zcxy.constant.CommonConstant;
import com.zcxy.core.bean.PageQuery;

import com.zcxy.exception.BusinessException;
import com.zcxy.mybatis.mapper.SysUserMapper;
import com.zcxy.mybatis.bean.CommonStringParam;
import com.zcxy.mybatis.bean.SysUser;
import com.zcxy.mybatis.service.BaseServiceImpl;
import com.zcxy.mybatis.util.RelationHelper;
import com.zcxy.sys.constant.Constant;
import com.zcxy.sys.entity.VerificationCode;
import com.zcxy.sys.pojo.*;
import com.zcxy.sys.service.ISysAttachmentService;
import com.zcxy.sys.service.ISysUserService;
import com.zcxy.sys.service.IVerificationCodeService;
import com.zcxy.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户Service业务层处理
 *
 * @author zcc
 * @email 860474958@qq.com
 * @date 2020-06-01
 */
@Service
@Slf4j
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser>
        implements ISysUserService {
    // 过期时间30分钟
    public static final long EXPIRE_TIME = 30 * 60 * 1000;
    private final Integer expiration = 2;


    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private ISysAttachmentService iSysAttachmentService;

    @Autowired
    private IVerificationCodeService iVerificationCodeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<SysUserVo> queryPageList(PageQuery<CommonStringParam> queryVo) {

        QueryWrapper queryWrapper = new QueryWrapper(new SysUser());
        if (queryVo.getT() != null && StringUtils.isNotEmpty(queryVo.getT().getQueryStr())) {
            queryWrapper.and(i -> {
                ((QueryWrapper) i).or(true).like(true, "login_name", queryVo.getT().getQueryStr()).
                        or(true).like("user_name", queryVo.getT().getQueryStr());
            });
            //queryWrapper.and(wrapper -> wrapper.like("login_name", queryVo.getT().getQueryStr()).or().like("user_name", queryVo.getT().getQueryStr()));
        }
        if (queryVo.getT() != null && StringUtils.isNotEmpty(queryVo.getT().getStatus())) {
            queryWrapper.and(i -> {
                ((QueryWrapper) i).eq("status", queryVo.getT().getStatus());
            });
            //queryWrapper.and(wrapper -> wrapper.like("login_name", queryVo.getT().getQueryStr()).or().like("user_name", queryVo.getT().getQueryStr()));
        }
        Page page = new Page(queryVo.getPageNo(), queryVo.getPageSize());

        IPage<SysUserVo> sysUserVoIPage =
                BeanCopierUtil.copyPage(baseMapper.selectPage(page, queryWrapper), SysUserVo.class);
        //处理工具数据
        List<SysUserVo> sysUserVos = sysUserVoIPage.getRecords();
        //去除全部的数据
        if (CollectionUtil.isNotEmpty(sysUserVos)) {
            List<SysUserVo> sysUserVosNotAllWorkSpace = sysUserVos.stream().filter(i -> {
                return !Constant.ALL.equals(i.getAllWorkspace());
            }).collect(Collectors.toList());
            RelationHelper.renderList(sysUserVosNotAllWorkSpace);
            sysUserVoIPage.setRecords(sysUserVos);
        }

        return sysUserVoIPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<SysUserVo> queryList() {
        SysUser sysUser = new SysUser();
        sysUser.setStatus(Constant.ENABLE);
        QueryWrapper queryWrapper = new QueryWrapper(sysUser);
        List<SysUser> sysUsers = baseMapper.selectList(queryWrapper);
        return BeanCopierUtil.copyListToList(sysUsers, SysUserVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSysUser(SysUser sysUser) {
        //1.TODO 校验用户数据  登录名
        validFiledExistInsert("loginName", sysUser.getLoginName(), "登录名不能重复");
        /* validFiledExistInsert("email", sysUser.getEmail(), "邮箱不能重复");*/
        //2.生成相关密码
        String password = "123456";
        String salt = RandomUtil.randomString(8);
        String passwordEncode = PasswordUtil.encrypt(sysUser.getLoginName(), password, salt);
        sysUser.setSalt(salt);
        sysUser.setPassword(passwordEncode);
        sysUser.setStatus(CommonConstant.STATUS_NORMAL);
        sysUser.setDelFlag(CommonConstant.DEL_FLAG_1);
        sysUser.setUserName(sysUser.getSurname() + sysUser.getName());
        //3.入数据库
        baseMapper.insert(sysUser);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSysUser(SysUserVo sysUser) {
        SysUser sysUserdb = baseMapper.selectById(sysUser.getId());
        if (!sysUser.getOldpassword().equals("")) {
            String passwordEncodeold =
                    PasswordUtil.encrypt(sysUserdb.getLoginName(), sysUser.getOldpassword(), sysUserdb.getSalt());
            if (passwordEncodeold.equals(sysUserdb.getPassword())) {
                throw new BusinessException("旧密码输入错误");
            }
        }
        validFiledExistUpdate("loginName", sysUser.getLoginName(), "id", sysUser.getId(), "登录名不能重复");

        if (!sysUser.getPassword().equals(sysUserdb.getPassword())) {

            String passwordEncode =
                    PasswordUtil.encrypt(sysUser.getLoginName(), sysUser.getPassword(), sysUserdb.getSalt());
            sysUser.setPassword(passwordEncode);
        }
        BeanCopierUtil.copyObject(sysUser, sysUserdb);
        sysUserdb.setUserName(sysUser.getSurname() + sysUser.getName());
        baseMapper.updateById(sysUserdb);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeSysUser(String id) {
        baseMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> removeAllSysUser(List<String> ids) {
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.in("id", ids);
        baseMapper.delete(queryWrapper);
        List<String> names = new ArrayList();

        return names;
    }

    @Override
    public void download(SysUser sysUser, HttpServletResponse response) throws IOException {
        List<SysUser> sysUsers = baseMapper.selectList(new QueryWrapper<>(sysUser));
        List<Map<String, Object>> list = new ArrayList<>();
        for (SysUser sysUserExcel : sysUsers) {
            Map<String, Object> map = new LinkedHashMap<>();
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDisable(List<String> ids) {
        updateByType(ids, Constant.DISABLE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateEnable(List<String> ids) {
        updateByType(ids, Constant.ENABLE);
    }

    @Override
    public SysUser selectbytoken() {
        String token = JwtUtil.getKVByHeadr(CommonConstant.X_ACCESS_TOKEN);
        String userId = JwtUtil.getKeyValue(token, "userId");
        SysUser sysUser = iSysUserService.getBaseMapper().selectById(userId);
        return sysUser;

    }

    public void updateByType(List<String> ids, String type) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in("id", ids);
        List<SysUser> sysUsers = baseMapper.selectList(queryWrapper);
        sysUsers.stream().forEach(i -> {
            if (Constant.ENABLE.equals(type)) {
                i.setStatus(Constant.ENABLE);
            } else if (Constant.DISABLE.equals(type)) {
                i.setStatus(Constant.DISABLE);
            }
        });
        saveOrUpdateBatch(sysUsers);

    }







    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginVo login(SysUserLoginDto sysUser) {
        String loginName = sysUser.getLoginName();
        String psw = sysUser.getPassword();
        //验证验证码
        //验证用户名密码
        SysUser sysUserCheck = checkUser(loginName, psw);
        LoginVo loginVo = new LoginVo();
        String  jwt=JwtUtil.createTokenByUser(sysUserCheck, sysUser.getPassword());
        loginVo.setToken("Bearer " + jwt);
        loginVo.setLoginName(loginName);
        loginVo.setAdmin(sysUserCheck.getAdmin());
        return loginVo;
    }

    public SysUser checkUser(String loginName, String pwd) {
        boolean ret = false;
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("login_name", loginName);
        List<SysUser> sysUsers = baseMapper.selectList(queryWrapper);
        if (sysUsers.size() < 1) {
            throw new BusinessException("用户名不存在");
        }
        String passwordEncode = PasswordUtil.encrypt(loginName, pwd, sysUsers.get(0).getSalt());
        if (!passwordEncode.equals(sysUsers.get(0).getPassword())) {
            throw new BusinessException("密码错误，请重新输入");
        }
        return sysUsers.get(0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EmailVo sendEmail(VerificationCode code) {
        EmailVo emailVo;
        String content;
        VerificationCode verificationCodeq = new VerificationCode();
        verificationCodeq.setStatus("1");
        verificationCodeq.setValue(code.getValue());
        VerificationCode verificationCode =
                iVerificationCodeService.getBaseMapper().selectOne(new QueryWrapper<>(verificationCodeq));

        // 如果不存在有效的验证码，就创建一个新的
        TemplateEngine engine =
                TemplateUtil.createEngine(new TemplateConfig("/template/email", TemplateConfig.ResourceMode.CLASSPATH));
        Template template = engine.getTemplate("email.ftl");

        if (verificationCode == null) {
            code.setCode(RandomUtil.randomNumbers(6));
            content = template.render(Dict.create().set("code", code.getCode()));
            emailVo = new EmailVo(Collections.singletonList(code.getValue()), "plmadmin 总控管理系统", content);
            code.setStatus("1");
            iVerificationCodeService.getBaseMapper().insert(code);
            timedDestruction(code);
            // 存在就再次发送原来的验证码
        } else {
            content = template.render(Dict.create().set("code", verificationCode.getCode()));
            emailVo = new EmailVo(Collections.singletonList(verificationCode.getValue()), "plmadmin 总控管理系统", content);
        }
        return emailVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void validated(VerificationCode code) {
        VerificationCode verificationCodeq = new VerificationCode();
        verificationCodeq.setStatus("1");
        verificationCodeq.setValue(code.getValue());
        VerificationCode verificationCode =
                iVerificationCodeService.getBaseMapper().selectOne(new QueryWrapper<>(verificationCodeq));
        if (verificationCode == null || !verificationCode.getCode().equals(code.getCode())) {
            throw new BusinessException("无效验证码");
        } else {
            verificationCode.setStatus("0");
            iVerificationCodeService.getBaseMapper().updateById(verificationCode);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePwd(SysUserResetPassWord code) {
        //根据
        SysUser sysUserq = new SysUser();
        SysUser sysUser;

        if (!StringUtils.isBlank(code.getLoginName())) {
            sysUserq.setLoginName(code.getLoginName());
        }
        if (!StringUtils.isBlank(code.getEmail())) {
            sysUserq.setEmail(code.getEmail());
        }
        sysUser = baseMapper.selectOne(new QueryWrapper<>(sysUserq));
        if (sysUser == null) {
            throw new BusinessException("用户名不存在");
        }
        String passwordEncode = PasswordUtil.encrypt(sysUser.getLoginName(), code.getPwd(), sysUser.getSalt());
        sysUser.setPassword(passwordEncode);
        baseMapper.updateById(sysUser);
    }

    /**
     * 定时任务，指定分钟后改变验证码状态
     *
     * verifyCode 验证码
     */
    private void timedDestruction(VerificationCode verifyCode) {
        //以下示例为程序调用结束继续运行
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        try {
            executorService.schedule(() -> {
                verifyCode.setStatus("0");
                iVerificationCodeService.getBaseMapper().updateById(verifyCode);
            }, expiration * 60 * 1000L, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkEmail(String email) {
        SysUser sysUser = new SysUser();
        sysUser.setEmail(email);
        int count = baseMapper.selectCount(new QueryWrapper(sysUser));
        if (count < 1) {
            throw new BusinessException("邮箱不存在");
        }
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void LoginOut() {
        //登出


    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysUser uploadObjectAttachment(String url, String id) {
        SysUser sysUser = baseMapper.selectById(id);
        sysUser.setUrl(url);
        baseMapper.updateById(sysUser);
        return sysUser;
    }

}
